package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.AccraditationRecordConstant;
import com.zzyl.constant.RetreatConstant;
import com.zzyl.dto.RetreatApplicationDto;
import com.zzyl.entity.*;
import com.zzyl.mapper.DeptMapper;
import com.zzyl.mapper.ElderMapper;
import com.zzyl.mapper.RetreatMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.service.AccraditationRecordService;
import com.zzyl.service.ActFlowCommService;
import com.zzyl.service.CheckoutService;
import com.zzyl.utils.CodeUtil;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.RecordVo;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CheckoutServiceImpl implements CheckoutService {

    @Autowired
    private RetreatMapper retreatMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private ElderMapper elderMapper;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private ActFlowCommService actFlowCommService;

    @Autowired
    private AccraditationRecordService accraditationRecordService;

    @Transactional
    @Override
    public ResponseResult createCheckOut(RetreatApplicationDto dto) {
        Elder elder = elderMapper.selectByPrimaryKey(dto.getElderId());
        if (ObjectUtil.isNotEmpty(elder) && elder.getStatus().equals(3)) {
            return ResponseResult.error(elder.getName() + "已经发起过退住申请!");
        }
        //获取线程中的用户信息
        String subject = UserThreadLocal.getSubject();
        User user = JSONUtil.toBean(subject, User.class);

        Retreat retreat = BeanUtil.toBean(dto, Retreat.class);

        //申请人
        retreat.setApplicat(user.getRealName());
        //申请人id
        retreat.setApplicatId(user.getId());
        //部门编号
        retreat.setDeptNo(user.getDeptNo());
        //标题
        retreat.setTitle(dto.getName() + "的退住申请");
        //flowStatus
        retreat.setFlowStatus(Retreat.FlowStatus.APPLY_APPROVAL.getCode());
        //createBy
        retreat.setCreateBy(user.getId());
        //retreatCode
        String retreatCode = CodeUtil.generateCode("TZ", redisTemplate, 5);
        retreat.setRetreatCode(retreatCode);
        //status
        retreat.setStatus(Retreat.Status.APPLICATION.getCode());
        //插入数据到退住表
        retreatMapper.createRetreat(retreat);

        //更新老人表状态
        elder.setStatus(3);
        elderMapper.updateByPrimaryKeySelective(elder);

        if (ObjectUtil.isNotEmpty(dto.getTaskId())) {
            //完成任务
            actFlowCommService.completeProcess(
                    retreat.getTitle(),
                    dto.getTaskId(),
                    user.getId().toString(),
                    1,
                    retreat.getStatus()
            );
        } else {
            //如果不存在,才需要设置流程变量和启动流程实例
            //        5,准备设置流程变量,业务key
            Map<String, Object> map = setVariables(retreat);
//        6,启动流程实例
            actFlowCommService.start(retreat.getId(), "retreat", user, map, true);
        }

        //9.1获取下一个审核人id
        Long nextAssigneeId = actFlowCommService.getNextAssignee("retreat", "retreat:" + retreat.getId());

        RecordVo recordVo = getRecordVo(
                retreat,
                user,
                AccraditationRecordConstant.AUDIT_STATUS_PASS,
                "同意",
                "发起申请-申请退住",
                "护理组组长处理-退住审批",
                nextAssigneeId,
                AccraditationRecordConstant.RECORD_HANDLE_TYPE_PROCESSED
        );

        accraditationRecordService.insert(recordVo);

        System.out.println("插入成功！");
        return ResponseResult.success();
    }
    /**
     * 获取操作记录RecordVo
     *
     * @param retreat        退住对象
     * @param user           当前用户
     * @param status         审批状态 1:通过 2:拒绝 3:驳回  4:撤回  5:撤销
     * @param option         意见
     * @param step           当前步骤
     * @param nextStep       下一个操作步骤
     * @param nextAssigneeId 下一个审核人id
     * @param handleType     处理类型 0:已审批 1：已处理
     * @return
     */
    public RecordVo getRecordVo(Retreat retreat, User user, Integer status, String option, String step, String nextStep, Long nextAssigneeId, Integer handleType) {
        RecordVo recordVo = new RecordVo();
        recordVo.setId(retreat.getId());
        recordVo.setType(AccraditationRecordConstant.RECORD_TYPE_RETREAT);
        recordVo.setFlowStatus(retreat.getFlowStatus());
        recordVo.setHandleType(handleType);
        recordVo.setStatus(status);
        recordVo.setOption(option);
        recordVo.setStep(step);
        recordVo.setNextStep(nextStep);
        recordVo.setRealName(user.getRealName());
        recordVo.setUserId(user.getId());
        recordVo.setNextAssignee(nextAssigneeId);
        return recordVo;
    }

    /**
     * 启动流程实例，如果当前登录人是第一个节点的执行人，则自动执行任务
     *
     * @param id                   业务id
     * @param processDefinitionKey 流程定义key
     * @param user                 当前登录用户
     * @param variables            流程变量参数
     * @param autoFinished         是否自动完成
     */
    private void start(Long id, String processDefinitionKey, User user, Map<String, Object> variables, boolean autoFinished) {

        String businessKey = processDefinitionKey + ":" + id;
        //启动流程实例
        startProcess(processDefinitionKey, variables, businessKey);

        //查询任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .taskAssignee(user.getId().toString())
                .list();
        //必须首节点
        list = list.stream().filter(t -> "0".equals(t.getFormKey())).collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(list) && autoFinished) {
            for (Task task : list) {
                Map<String, Object> variables2 = new HashMap<>();
                variables2.put("processStatus", 1);
                variables2.put("ops", 1);

                taskService.complete(task.getId(), variables2);
            }
        }

    }

    /**
     * 启动流程实例
     *
     * @param processDefinitionKey
     * @param variables
     * @param businessKey
     */
    private ProcessInstance startProcess(String processDefinitionKey, Map<String, Object> variables, String businessKey) {
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
        return processInstance;
    }
    //123
    //实验

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private UserMapper userMapper;

    /**
     * 准备流程变量
     *
     * @param retreat
     * @return
     */
    private Map<String, Object> setVariables(Retreat retreat) {
        //设置流程变量
        Map<String, Object> variables = new HashMap<>();
        //护理员
        variables.put("assignee0", retreat.getApplicatId());
        //退住单的其他信息
        variables.put("assignee0Name", retreat.getApplicat());
        variables.put("processTitle", retreat.getTitle());

        //护理组主管
        Dept dept = deptMapper.selectByDeptNo(RetreatConstant.NURSING_DEPT_CODE);
        variables.put("assignee1", dept.getLeaderId());
        //法务员工
        List<Long> legatUserIdList = userMapper.selectByDeptNo(RetreatConstant.DEAN_OFFICE_DEPT_CODE);
        variables.put("assignee2", legatUserIdList.get(legatUserIdList.size() - 1));

        //结算员
        List<Long> cashierList = userMapper.selectByDeptNoPostNo(RetreatConstant.SETTLEMENT_DEPT_CODE, RetreatConstant.POST_NO_CASHIER);
        variables.put("assignee3", cashierList.get(0));

        //结算组主管
        List<Long> leaderList = userMapper.selectByDeptNoPostNo(RetreatConstant.SETTLEMENT_DEPT_CODE, RetreatConstant.POST_NO_LEADER);
        variables.put("assignee4", leaderList.get(0));


        //副院长
        List<Long> Dean = userMapper.selectByDeptNo(RetreatConstant.DEAN_OFFICE_DEPT_CODE);
        variables.put("assignee5", Dean.get(0));

        //结算员
        variables.put("assignee6", cashierList.get(0));

        //设置流程类型   退住
        variables.put("processType", 1);

        //流程类型code
        variables.put("processCode", retreat.getRetreatCode());

        //流程类型 状态
        variables.put("processStatus", 1);
        //设置申请时间
        variables.put("applicationTime", retreat.getCreateTime());

        //设置退住主键id
        variables.put("processCheckInId", retreat.getId());
        return variables;
    }
}
